<script setup lang="ts">
import { ref, onMounted, watch, computed, onUnmounted } from 'vue'
import * as echarts from 'echarts/core'
import { LineChart, BarChart } from 'echarts/charts'
import {
  TitleComponent,
  TooltipComponent,
  GridComponent,
  DataZoomComponent,
  LegendComponent,
  ToolboxComponent,
  MarkLineComponent,
  MarkAreaComponent
} from 'echarts/components'
import { CanvasRenderer } from 'echarts/renderers'
import { useElementSize } from '@vueuse/core'
import type { EChartsType } from 'echarts/core'

// 定义数据项接口
interface TrendDataItem {
  date: string;
  positive: number;
  neutral: number;
  negative: number;
}

// 定义异常点接口
interface AnomalyPoints {
  positive: number[];
  negative: number[];
}

// 定义峰值和谷值接口
interface PeaksAndValleys {
  peaks: number[];
  valleys: number[];
}

// 定义标记点数据接口
interface MarkPointDataItem {
  name: string;
  value: number;
  xAxis: number;
  yAxis: number;
  itemStyle: {
    color: string;
  };
}

// 定义标记区域数据接口
interface MarkAreaDataItem {
  name?: string;
  xAxis: number;
}

// 注册必要的组件
echarts.use([
  TitleComponent,
  TooltipComponent,
  GridComponent,
  LineChart,
  BarChart,
  CanvasRenderer,
  DataZoomComponent,
  LegendComponent,
  ToolboxComponent,
  MarkLineComponent,
  MarkAreaComponent
])

const props = defineProps({
  data: {
    type: Array as () => TrendDataItem[],
    required: true,
    default: () => []
  },
  timeUnit: {
    type: String,
    default: 'hour'
  },
  showDataZoom: {
    type: Boolean,
    default: true
  },
  showMarkPoints: {
    type: Boolean,
    default: true
  },
  height: {
    type: String,
    default: '400px'
  },
  theme: {
    type: String,
    default: ''
  },
  anomalyThreshold: {
    type: Number,
    default: 0.5
  }
})

const chartRef = ref<HTMLElement | null>(null)
const { width, height } = useElementSize(chartRef)
const chart = ref<EChartsType | null>(null)

// 计算异常点
const anomalies = computed<AnomalyPoints>(() => {
  if (!props.data || props.data.length === 0) return { positive: [], negative: [] }
  
  const positiveAnomalies: number[] = []
  const negativeAnomalies: number[] = []
  
  // 找出情感数值异常的点
  props.data.forEach((item: TrendDataItem, index: number) => {
    if (index === 0 || index === props.data.length - 1) return
    
    const prev: TrendDataItem = props.data[index - 1]
    const next: TrendDataItem = props.data[index + 1]
    
    // 计算正面情感变化率
    const positiveDiffPrev = Math.abs(item.positive - prev.positive)
    const positiveDiffNext = Math.abs(item.positive - next.positive)
    
    // 计算负面情感变化率
    const negativeDiffPrev = Math.abs(item.negative - prev.negative)
    const negativeDiffNext = Math.abs(item.negative - next.negative)
    
    // 判断是否为异常点
    if (positiveDiffPrev > props.anomalyThreshold && positiveDiffNext > props.anomalyThreshold) {
      positiveAnomalies.push(index)
    }
    
    if (negativeDiffPrev > props.anomalyThreshold && negativeDiffNext > props.anomalyThreshold) {
      negativeAnomalies.push(index)
    }
  })
  
  return { positive: positiveAnomalies, negative: negativeAnomalies }
})

// 计算高峰期和低谷期
const peaksAndValleys = computed<PeaksAndValleys>(() => {
  if (!props.data || props.data.length < 5) return { peaks: [], valleys: [] }
  
  const peaks: number[] = []
  const valleys: number[] = []
  const windowSize = 5 // 用于计算移动平均
  
  // 计算移动平均
  const movingAvg: { index: number; value: number }[] = []
  for (let i = 0; i < props.data.length - windowSize + 1; i++) {
    let sum = 0
    for (let j = 0; j < windowSize; j++) {
      sum += props.data[i + j].positive + props.data[i + j].negative
    }
    movingAvg.push({ index: i + Math.floor(windowSize / 2), value: sum / windowSize })
  }
  
  // 寻找峰值和谷值
  for (let i = 1; i < movingAvg.length - 1; i++) {
    if (movingAvg[i].value > movingAvg[i - 1].value && movingAvg[i].value > movingAvg[i + 1].value) {
      peaks.push(movingAvg[i].index)
    }
    if (movingAvg[i].value < movingAvg[i - 1].value && movingAvg[i].value < movingAvg[i + 1].value) {
      valleys.push(movingAvg[i].index)
    }
  }
  
  // 选择最显著的几个峰值和谷值
  peaks.sort((a, b) => {
    const aValue = props.data[a].positive + props.data[a].negative
    const bValue = props.data[b].positive + props.data[b].negative
    return bValue - aValue
  })
  
  valleys.sort((a, b) => {
    const aValue = props.data[a].positive + props.data[a].negative
    const bValue = props.data[b].positive + props.data[b].negative
    return aValue - bValue
  })
  
  return {
    peaks: peaks.slice(0, 3), // 取前3个峰值
    valleys: valleys.slice(0, 3) // 取前3个谷值
  }
})

// 处理窗口大小变化
const handleResize = (): void => {
  if (chart.value) {
    chart.value.resize()
  }
}

// 初始化图表
const initChart = (): void => {
  if (!chartRef.value) return
  
  // 销毁之前的实例
  if (chart.value) {
    chart.value.dispose()
  }
  
  // 创建图表实例
  chart.value = echarts.init(chartRef.value, props.theme)
  
  // 窗口大小变化时，重新调整图表大小
  window.addEventListener('resize', handleResize)
  
  // 更新图表
  updateChart()
}

// 更新图表
const updateChart = (): void => {
  if (!chart.value || !props.data || props.data.length === 0) return
  
  const times = props.data.map((item: TrendDataItem) => item.date)
  const positiveData = props.data.map((item: TrendDataItem) => item.positive)
  const neutralData = props.data.map((item: TrendDataItem) => item.neutral)
  const negativeData = props.data.map((item: TrendDataItem) => item.negative)
  const totalData = props.data.map((item: TrendDataItem) => item.positive + item.neutral + item.negative)
  
  // 计算最大值以设置Y轴范围
  const maxValue = Math.max(...totalData) * 1.2
  
  // 准备标记点数据
  const markPointData: MarkPointDataItem[] = []
  const markAreaData: [MarkAreaDataItem, MarkAreaDataItem][] = []
  
  // 添加异常点标记
  if (props.showMarkPoints) {
    anomalies.value.positive.forEach(index => {
      markPointData.push({
        name: '正面异常',
        value: positiveData[index],
        xAxis: index,
        yAxis: positiveData[index],
        itemStyle: { color: '#67C23A' }
      })
    })
    
    anomalies.value.negative.forEach(index => {
      markPointData.push({
        name: '负面异常',
        value: negativeData[index],
        xAxis: index,
        yAxis: negativeData[index],
        itemStyle: { color: '#F56C6C' }
      })
    })
  }
  
  // 添加高峰期和低谷期标记
  peaksAndValleys.value.peaks.forEach(index => {
    markAreaData.push([
      { name: '高峰', xAxis: Math.max(0, index - 2) },
      { xAxis: Math.min(times.length - 1, index + 2) }
    ])
  })
  
  peaksAndValleys.value.valleys.forEach(index => {
    markAreaData.push([
      { name: '低谷', xAxis: Math.max(0, index - 2) },
      { xAxis: Math.min(times.length - 1, index + 2) }
    ])
  })
  
  const option = {
    title: {
      text: '情感趋势分析',
      subtext: `按${props.timeUnit === 'hour' ? '小时' : props.timeUnit === 'day' ? '天' : props.timeUnit === 'week' ? '周' : '月'}展示`,
      left: 'center'
    },
    tooltip: {
      trigger: 'axis',
      axisPointer: {
        type: 'cross',
        label: {
          backgroundColor: '#6a7985'
        }
      },
      formatter: function(params: any[]): string {
        let result = params[0].name + '<br/>';
        params.forEach(item => {
          let colorSpan = `<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${item.color};"></span>`;
          result += colorSpan + item.seriesName + ': ' + item.value + '<br/>';
        });
        return result;
      }
    },
    legend: {
      data: ['正面情感', '中性情感', '负面情感', '情感总量'],
      top: 30
    },
    toolbox: {
      feature: {
        saveAsImage: { title: '保存为图片' },
        dataView: { title: '数据视图', lang: ['数据视图', '关闭', '刷新'] },
        magicType: {
          title: {
            line: '切换为折线图',
            bar: '切换为柱状图',
            stack: '切换为堆叠',
            tiled: '切换为平铺'
          },
          type: ['line', 'bar', 'stack', 'tiled']
        },
        restore: { title: '还原' }
      }
    },
    grid: {
      left: '3%',
      right: '4%',
      bottom: props.showDataZoom ? '15%' : '8%',
      top: '15%',
      containLabel: true
    },
    xAxis: [
      {
        type: 'category',
        boundaryGap: false,
        data: times,
        axisLabel: {
          rotate: 45,
          fontSize: 12,
          formatter: function(value: string): string {
            if (props.timeUnit === 'hour') {
              return value;
            } else if (props.timeUnit === 'day') {
              return value.substring(5); // 只显示月日
            } else {
              return value;
            }
          }
        }
      }
    ],
    yAxis: [
      {
        type: 'value',
        name: '情感值',
        max: maxValue,
        splitLine: {
          show: true,
          lineStyle: {
            type: 'dashed'
          }
        }
      }
    ],
    dataZoom: props.showDataZoom ? [
      {
        type: 'slider',
        show: true,
        xAxisIndex: [0],
        start: 0,
        end: 100
      },
      {
        type: 'inside',
        xAxisIndex: [0],
        start: 0,
        end: 100
      }
    ] : [],
    series: [
      {
        name: '正面情感',
        type: 'line',
        stack: '情感',
        areaStyle: {
          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
            { offset: 0, color: 'rgba(103, 194, 58, 0.6)' },
            { offset: 1, color: 'rgba(103, 194, 58, 0.1)' }
          ])
        },
        emphasis: {
          focus: 'series'
        },
        data: positiveData,
        itemStyle: {
          color: '#67C23A'
        },
        lineStyle: {
          width: 2
        },
        markPoint: {
          symbolSize: 50,
          data: markPointData.filter(item => item.name === '正面异常')
        }
      },
      {
        name: '中性情感',
        type: 'line',
        stack: '情感',
        areaStyle: {
          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
            { offset: 0, color: 'rgba(144, 147, 153, 0.6)' },
            { offset: 1, color: 'rgba(144, 147, 153, 0.1)' }
          ])
        },
        emphasis: {
          focus: 'series'
        },
        data: neutralData,
        itemStyle: {
          color: '#909399'
        },
        lineStyle: {
          width: 2
        }
      },
      {
        name: '负面情感',
        type: 'line',
        stack: '情感',
        areaStyle: {
          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
            { offset: 0, color: 'rgba(245, 108, 108, 0.6)' },
            { offset: 1, color: 'rgba(245, 108, 108, 0.1)' }
          ])
        },
        emphasis: {
          focus: 'series'
        },
        data: negativeData,
        itemStyle: {
          color: '#F56C6C'
        },
        lineStyle: {
          width: 2
        },
        markPoint: {
          symbolSize: 50,
          data: markPointData.filter(item => item.name === '负面异常')
        }
      },
      {
        name: '情感总量',
        type: 'line',
        smooth: true,
        emphasis: {
          focus: 'series'
        },
        data: totalData,
        itemStyle: {
          color: '#409EFF'
        },
        lineStyle: {
          width: 3,
          type: 'dashed'
        },
        symbol: 'circle',
        symbolSize: 8,
        markArea: {
          silent: true,
          itemStyle: {
            opacity: 0.2
          },
          data: markAreaData
        }
      }
    ]
  }
  
  chart.value.setOption(option)
}

// 监听数据变化
watch(() => props.data, () => {
  updateChart()
}, { deep: true })

// 监听尺寸变化
watch([width, height], () => {
  if (chart.value) {
    chart.value.resize()
  }
})

onMounted(() => {
  initChart()
})

onUnmounted(() => {
  // 移除事件监听器
  window.removeEventListener('resize', handleResize)
  
  // 销毁图表实例
  if (chart.value) {
    chart.value.dispose()
    chart.value = null
  }
})
</script>

<template>
  <div class="sentiment-trend-analysis">
    <div ref="chartRef" :style="{ height, width: '100%' }"></div>
  </div>
</template>

<style scoped>
.sentiment-trend-analysis {
  width: 100%;
  overflow: hidden;
}
</style> 